package service

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"go.uber.org/zap"
	"go-file-perception-model/internal/config"
	"go-file-perception-model/internal/logger"
)

// FileCollector 文件收集器
type FileCollector struct {
	config *config.FileIndexConfig
}

// NewFileCollector 创建文件收集器实例
func NewFileCollector(cfg *config.FileIndexConfig) *FileCollector {
	return &FileCollector{
		config: cfg,
	}
}

// CollectFiles 收集目录中的文件
func (c *FileCollector) CollectFiles(dir string, recursive bool) ([]string, error) {
	var files []string

	// 遍历目录
	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// 跳过目录
		if info.IsDir() {
			// 检查是否是需要排除的目录
			for _, excludeDir := range c.config.ExcludeDirs {
				if strings.Contains(path, excludeDir) {
					return filepath.SkipDir
				}
			}
			return nil
		}

		// 检查文件扩展名
		ext := strings.ToLower(filepath.Ext(path))
		supported := false
		for _, supportedExt := range c.config.SupportedExtensions {
			if ext == supportedExt {
				supported = true
				break
			}
		}

		if !supported {
			return nil
		}

		// 检查文件大小
		if info.Size() > c.config.MaxFileSize {
			logger.Warn("File too large, skipping", zap.String("file", path), zap.Int64("size", info.Size()))
			return nil
		}

		files = append(files, path)
		return nil
	})

	if err != nil {
		return nil, fmt.Errorf("failed to walk directory: %w", err)
	}

	return files, nil
}

// IsFileSupported 检查文件是否支持
func (c *FileCollector) IsFileSupported(filePath string) bool {
	ext := strings.ToLower(filepath.Ext(filePath))
	for _, supportedExt := range c.config.SupportedExtensions {
		if ext == supportedExt {
			return true
		}
	}
	return false
}

// IsDirectoryExcluded 检查目录是否被排除
func (c *FileCollector) IsDirectoryExcluded(dirPath string) bool {
	for _, excludeDir := range c.config.ExcludeDirs {
		if strings.Contains(dirPath, excludeDir) {
			return true
		}
	}
	return false
}

// GetFileSize 获取文件大小
func (c *FileCollector) GetFileSize(filePath string) (int64, error) {
	info, err := os.Stat(filePath)
	if err != nil {
		return 0, err
	}
	return info.Size(), nil
}

// IsFileSizeValid 检查文件大小是否有效
func (c *FileCollector) IsFileSizeValid(filePath string) bool {
	size, err := c.GetFileSize(filePath)
	if err != nil {
		return false
	}
	return size <= c.config.MaxFileSize
}